#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Weverything"
#pragma clang diagnostic warning "-Wextra"
#pragma clang diagnostic warning "-Wall"
#include "player.napi.h"
#include "player.user.hpp"
#include "taihe/array.hpp"
#include "PlayerNative.h"
inline bool _taihe_get_msb(uint64_t dig) {
    return dig >> (sizeof(uint64_t) * 8 - 1) != 0;
}
inline bool _taihe_get_sign(taihe::array_view<uint64_t> num) {
    return _taihe_get_msb(num[num.size() - 1]);
}
inline std::pair<bool, taihe::array<uint64_t>> _taihe_get_sign_and_abs(taihe::array_view<uint64_t> num) {
    uint64_t *buf = reinterpret_cast<uint64_t *>(malloc(num.size() * sizeof(uint64_t)));
    bool sign = _taihe_get_msb(num[num.size() - 1]);
    if (sign) {
        bool carry = true;
        for (std::size_t i = 0; i < num.size(); i++) {
            buf[i] = ~num[i] + carry;
            carry = carry && (buf[i] == 0);
        }
    } else {
        for (std::size_t i = 0; i < num.size(); i++) {
            buf[i] = num[i];
        }
    }
    std::size_t size = num.size();
    while (size > 0 && buf[size - 1] == 0) {
        size--;
    }
    return {sign, taihe::array<uint64_t>(buf, size)};
}
inline taihe::array<uint64_t> _taihe_build_num(bool sign, taihe::array_view<uint64_t> abs) {
    uint64_t *buf = reinterpret_cast<uint64_t *>(malloc((abs.size() + 1) * sizeof(uint64_t)));
    if (sign) {
        bool carry = true;
        for (std::size_t i = 0; i < abs.size(); i++) {
            buf[i] = ~abs[i] + carry;
            carry = carry && (buf[i] == 0);
        }
        buf[abs.size()] = carry - 1;
    } else {
        for (std::size_t i = 0; i < abs.size(); i++) {
            buf[i] = abs[i];
        }
        buf[abs.size()] = 0;
    }
    std::size_t size = abs.size() + 1;
    while (size >= 2 && ((buf[size - 1] == 0 && _taihe_get_msb(buf[size - 2]) == 0) ||
                        (buf[size - 1] == static_cast<uint64_t>(-1) && _taihe_get_msb(buf[size - 2]) == 1))) {
        size--;
    }
    return taihe::array<uint64_t>(buf, size);
}
static napi_value player_playNative_NAPI(napi_env env, [[maybe_unused]] napi_callback_info info) {
    size_t argc = 4;
    napi_value args[4] = {nullptr};
    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args , nullptr, nullptr));
    int32_t value0_tmp;
    NAPI_CALL(env, napi_get_value_int32(env, args[0], &value0_tmp));
    int32_t value0 = value0_tmp;
    int64_t value1_tmp;
    NAPI_CALL(env, napi_get_value_int64(env, args[1], &value1_tmp));
    int64_t value1 = value1_tmp;
    int64_t value2_tmp;
    NAPI_CALL(env, napi_get_value_int64(env, args[2], &value2_tmp));
    int64_t value2 = value2_tmp;
    struct value3_cpp_impl_t {
        napi_env env;
        napi_ref ref;
        value3_cpp_impl_t(napi_env env, napi_value callback): env(env), ref(nullptr) {
            NAPI_CALL(env, napi_create_reference(env, callback, 1, &ref));
        }
        ~value3_cpp_impl_t() {
            if (ref) {
                NAPI_CALL(env, napi_delete_reference(env, ref));
            }
        }
        void operator()() {
            napi_value napi_argv[] = {};
            napi_value napi_result = nullptr;
            napi_value cb_ref = nullptr, global = nullptr;
            NAPI_CALL(env, napi_get_reference_value(env, ref, &cb_ref));
            napi_get_global(env, &global);
            NAPI_CALL(env, napi_call_function(env, global, cb_ref, 1, napi_argv, &napi_result));
            return;
        }
    };
    ::taihe::callback<void()> value3 = ::taihe::make_holder<value3_cpp_impl_t, ::taihe::callback<void()>>(env, args[3]);

    player::playNative(value0, value1, value2, value3);
    napi_value result = nullptr;
    napi_get_undefined(env, &result);
    return result;
}
EXTERN_C_START
napi_value Init__player(napi_env env, napi_value exports) {
    if (::taihe::get_env() == nullptr) {
        ::taihe::set_env(env);
    }
    napi_property_descriptor desc[] = {
        {"playNative", nullptr, player_playNative_NAPI, nullptr, nullptr, nullptr, napi_default, nullptr}, 
    };
    NativeXComponentSample::PluginManager::GetInstance()->Export(env, exports);
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
EXTERN_C_END
#pragma clang diagnostic pop
